home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-09-21 | 39.3 KB | 1,279 lines | [TEXT/ALFA] |
- #############################################################################
- # MacPerl.tcl
- # -----------
- #
- # This is a set of routines that allow Alpha to act as a front end for the
- # standalone MacPerl application and that allow Perl scripts to be used as
- # text filters in Alpha. These functions are accessed through a special
- # MacPerl menu.
- #
- # To install the menu, choose "MacPerl" from the "Utils/Install" menu.
- #
- # The features of this package are explained in the file "MacPerl Help",
- # accessible from the Help menu.
- #
- #############################################################################
- #
- # If you don't already have MacPerl, it's available by anonymous ftp from
- # the umich site
- #
- # mac.archive.umich.edu [141.211.165.34] mac/development/languages (4)
- #
- # and its mirrors. Also, MacPerl's home site is
- #
- # ftp.switch.ch [130.59.1.40] software/mac/src/mpw_c
- #
- # MacPerl was written (ported to the Mac) by
- # Matthias Neeracher <neeri@iis.ee.ethz.ch> , and
- # Tim Endres <time@ice.com>.
- #
- #############################################################################
- # Authors: W. Thomas Pollard (pollard@chem.columbia.edu)
- # Martijn Koster (m.koster@nexor.co.uk)
- #
- # Version History:
- #
- # 1.5 9/94 - MacPerl menu rearranged somewhat.
- # Explicit "Get Output Window" command added to menu.
- # Reading "#!" line for args is incompatible w/ standard,
- # so it's been dropped.
- # Only scan the first 40 output lines for error messages (faster)
- # "wrapFilterScript" no longer opens STDIN
- # Text filters may now use command-line args
- # STDIN for text filters passed as explicit cmd-line arg
- # 1.4 9/94 - The "#!" line of every script is read for command-line args,
- # which are passed explicitly to MacPerl with the script.
- # "PromptForArgs" menu flag added.
- # "perlCmdlineArgs" modeVar holds default command-line args.
- # Scripts are sent using custom "perlDoScript2" proc, which
- # allows passing of explicit command-line args.
- # 1.3 9/94 - When any script generates a compilation error, the file
- # containing the script is brought up with the offending
- # line highlighted; all error output is also written to
- # a "Perl Error Messages" window.
- # 'repeatLastFilter' runs again the last text-filter script used.
- # 'perlLastFilter' modeVar holds pathname of last filter.
- # Menu flags now mirrored as modeVars, so they can be saved and
- # restored between sessions.
- # Minor bug fixes.
- # 1.2 8/94 - 'retrieveOutput' and 'autoSwitch' flags added.
- # 'openInMacperl' added.
- # MacPerl output window now closed before new scripts are sent.
- # Filters now abort if there are compilation errors, and
- # MacPerl diagnostic output retrieved and displayed in Alpha.
- # 1.1 8/94 - 'quitMacperl' added.
- # perl-mode file-marking updated for Alpha 5.90
- # Simplified installation via 'loadMacperl'(Pete Keleher).
- # 1.0 7/94 - perl-mode setup updated for Alpha 5.85:
- # keyword colorization supported
- # custom file-marking added
- # #! lines in filter scripts now handled correctly
- # Workarounds installed for AppleEvent bug in MacPerl 4.1.3
- # 0.9 3/94 - perl-mode stuff added, and
- # highlighted 'Perl commands' file (man page) prepared
- # minor bug fixes, too
- # 0.8 3/94 - flags are now check-marked
- # 0.7 3/94 - nested Text Filters folder now supported
- # menu format modified somewhat
- # 0.6 3/94 - 'applyToBuffer' flag added
- # scripts in Alpha buffers can now be used as filters
- # 0.5 2/94 - 'filters', 'open special' submenu added
- # 'overwrite' flag added
- # 0.2 1/94 - menu support added (MK)
- # 'execute selection', 'execute buffer' commands added
- # 0.1 9/93 - text filter functionality created (WTP)
- #
- # Comments, suggestions, bug reports, etc., should be directed to
- # Tom Pollard (pollard@chem.columbia.edu).
- #
- #############################################################################
- # Default settings for the Perl menu flags
- #
- set perlGetOutput 1
- set perlAutoSwitch 1
- set perlOverwrite 0
- set perlUsebuffer 1
- set perlPromptArgs 0
-
- set perlPrevScript {*startup*}
- set perlCmdlineArgs {}
-
- # Make duplicate copies of these variables as modeVars, taking responsibility
- # for keeping the two sets consistent (argh!)
-
- newModeVar Perl perlGetOutput $perlGetOutput 1
- newModeVar Perl perlAutoSwitch $perlAutoSwitch 1
- newModeVar Perl perlOverwrite $perlOverwrite 1
- newModeVar Perl perlUsebuffer $perlUsebuffer 1
- newModeVar Perl perlPromptArgs $perlPromptArgs 1
-
- newModeVar Perl perlLastFilter $perlPrevScript 0
- newModeVar Perl perlCmdlineArgs $perlCmdlineArgs 0
-
- #############################################################################
- # To install the MacPerl package, the user is prompted to locate his
- # MacPerl application. This information (necessary for building the MacPerl
- # menu) recorded in UserStartup.tcl, along with commands that will load
- # MacPerl mode automatically in the future.
- #
- proc loadMacPerl {} {
- global macperlPath mode modeMenus HOME
- set name [lindex [winNames -f] 0]
-
- if {[askyesno "Install the MacPerl menu?"] == "yes"} {
- set f [getfile {Where is your MacPerl application?"}]
-
- # modify UserStartup.tcl so that Perl menu loads automatically
- addUserLine "\r\# The next three lines enable the MacPerl menu."
- addUserLine "set macperlPath \"$f\""
- addUserLine "source \"\$HOME:Tcl:UserCode:MacPerl.tcl\""
- addUserLine "enableMenuItem -m install MacPerl 0"
-
- # enable Perl menu for this session
- set macperlPath $f
-
- if {[askyesno "Display MacPerl menu in Text mode?"] == "yes"} {
- addUserLine "lappend modeMenus(Text) {perlMenu}"
- lappend modeMenus(Text) {perlMenu}
- }
-
- if {[askyesno "Copy sample Text Filters to your MacPerl folder?"] == "yes"} {
- if {[catch {cpdir "$HOME:Tcl:UserCode:Text Filters" [macperlFolder]}]} {
- alertnote "Text Filters folder couldn't be copied"
- } else {
- alertnote "Text Filters folder was successfully copied"
- }
- }
-
- rebuildPerlMenu
- enableMenuItem -m install "MacPerl" 0
-
- # reset the mode, so that Perl menu is inserted if required
- set currentMode $mode
- changeMode none
- changeMode $currentMode
- }
- }
-
- #############################################################################
- # Return paths to standard files, based on the path to MacPerl:
- #
- proc macperlFolder {} {
- global macperlPath
- regexp {(.*):([^:]*)} $macperlPath pathname dirname filename
- return ${dirname}:
- }
-
- proc stdinPath {} {
- return [macperlFolder]STDIN
- }
-
- proc stdoutPath {} {
- return [macperlFolder]STDOUT
- }
-
- proc scriptPath {} {
- return [macperlFolder]SCRIPT
- }
-
- proc scriptFolder {} {
- return "[macperlFolder]Text Filters:"
- }
-
- #############################################################################
- # This is a generally useful proc that builds a hierarchical menu
- # from the files in a given folder and all subfolders. As the menu is
- # built, the pathnames of the various files are saved in the array
- # indicated by $filePaths. The index of the file's path in this array
- # is formed by concatenating the submenu name and filename, allowing the
- # pathname to be retrieved by the procedure $proc when the menu item is
- # selected.
- #
- proc buildSubMenu {folder name proc filePaths} {
- global $filePaths
- if {$name == 0} {
- set name [file tail [file dirname $folder]]
- }
- if {$proc == 0} {
- set pproc ""
- } else {
- set pproc "-p $proc"
- }
- set menu {}
- set filenames [glob -nocomplain $folder\*]
- if {[llength $filenames] > 0} {
- foreach m $filenames {
- if {[file isdirectory $m]} {
- lappend menu [buildSubMenu ${m}: 0 $proc $filePaths]
- } elseif {[file isfile $m]} {
- set fname [file tail $m]
- lappend menu $fname
- set ${filePaths}($name:$fname) $m
- }
- }
- }
- return [concat {menu -m -n} [list $name] $pproc [list $menu]]
- }
-
- #############################################################################
- # Build a submenu of "preattached" Perl filters using the names of the
- # scripts in the Text Filters directory
- #
- proc perlFilterMenu {} {
- global perlFilterPath
- set scriptDir [scriptFolder]
- if {![file exists $scriptDir]} {
- cd [macperlFolder]
- mkdir {Text Filters}
- alertnote "Creating new \"Text Filters\" folder in MacPerl folder"
- cd
- }
- return [buildSubMenu $scriptDir TextFilters textFiltersProc perlFilterPath]
- }
-
- #############################################################################
- # Build the perl menu
- #
- proc rebuildPerlMenu {} {
- global perlMenu perlOverwrite perlUsebuffer perlGetOutput perlAutoSwitch
- global perlPrevScript perlPromptArgs
-
- set perlMenu "•132"
- menu -n $perlMenu [ concat {
- "macperl"
- {menu -m -n "tellMacperl..." -p perlTellProc {
- "Open This File"
- "Get Output Window"
- "Quit"
- }
- }
- "(-"
- "runTheSelection"
- "runTheBuffer"
- "runAFile"
- "(-"
- } [list [perlFilterMenu]] {
- {menu -n OtherTextFilters {
- "selectABuffer"
- "selectAFile"
- }
- }
- "repeatLastFilter"
- {menu -m -n openSpecial -p perlOpenFile {
- "STDIN"
- "STDOUT"
- "SCRIPT"
- }
- }
- "(-"
- "retrieveOutput"
- "autoSwitch"
- "promptForArgs"
- "applyToBuffer"
- "overwriteSelection"
- "(-"
- "rebuildPerlMenu"
- } ]
-
- markMenuItem $perlMenu retrieveOutput $perlGetOutput
- markMenuItem $perlMenu autoSwitch $perlAutoSwitch
- markMenuItem $perlMenu overwriteSelection $perlOverwrite
- markMenuItem $perlMenu applyToBuffer $perlUsebuffer
- markMenuItem $perlMenu promptForArgs $perlPromptArgs
- if {$perlPrevScript == {} || $perlPrevScript == {*startup*}} {
- enableMenuItem $perlMenu repeatLastFilter 0
- }
- }
-
- if ([info exists macperlPath]) {
- rebuildPerlMenu
- }
-
- # Keep global vars and modeVars consistent.
- #
- trace variable PerlmodeVars(perlOverwrite) w shadowPerl
- trace variable PerlmodeVars(perlUsebuffer) w shadowPerl
- trace variable PerlmodeVars(perlGetOutput) w shadowPerl
- trace variable PerlmodeVars(perlAutoSwitch) w shadowPerl
- trace variable PerlmodeVars(perlPromptArgs) w shadowPerl
- trace variable PerlmodeVars(perlLastFilter) w shadowPerl
- trace variable PerlmodeVars(perlCmdlineArgs) w shadowPerl
-
- # ShadowPerl sets the global vars when the mode vars are modified and
- # keeps the menu checkmarked correctly.
- #
- proc shadowPerl {name1 name2 op} {
- global perlMenu perlOverwrite perlUsebuffer perlGetOutput perlAutoSwitch
- global perlPromptArgs perlPrevScript perlCmdlineArgs
- global PerlmodeVars
- if {$name1 == "PerlmodeVars" && $op == "w"} {
- switch $name2 {
- "perlOverwrite" {
- set perlOverwrite $PerlmodeVars(perlOverwrite)
- markMenuItem $perlMenu overwriteSelection $perlOverwrite
- }
- "perlUsebuffer" {
- set perlUsebuffer $PerlmodeVars(perlUsebuffer)
- markMenuItem $perlMenu applyToBuffer $perlUsebuffer
- }
- "perlGetOutput" {
- set perlGetOutput $PerlmodeVars(perlGetOutput)
- markMenuItem $perlMenu retrieveOutput $perlGetOutput
- }
- "perlAutoSwitch" {
- set perlAutoSwitch $PerlmodeVars(perlAutoSwitch)
- markMenuItem $perlMenu autoSwitch $perlAutoSwitch
- }
- "perlPromptArgs" {
- set perlPromptArgs $PerlmodeVars(perlPromptArgs)
- markMenuItem $perlMenu promptForArgs $perlPromptArgs
- }
- "perlCmdlineArgs" {
- set perlCmdlineArgs $PerlmodeVars(perlCmdlineArgs)
- }
- "perlLastFilter" {
- # Don't allow perlPrevScript to be changed from the flags menu
- if {$perlPrevScript == "*startup*"} {
- set perlPrevScript $PerlmodeVars(perlLastFilter)
- enableMenuItem $perlMenu repeatLastFilter 1
- } else {
- set PerlmodeVars(perlLastFilter) $perlPrevScript
- }
- }
- default {
- return
- }
- }
- }
- }
-
- #############################################################################
- # Menu commands
- #############################################################################
-
- ############################################################################
- # Toggle the perl menu flags
- #
- proc retrieveOutput {} {
- global perlMenu PerlmodeVars perlGetOutput modifiedModeVars
- lappend modifiedModeVars perlGetOutput
- if {$perlGetOutput} then {
- set PerlmodeVars(perlGetOutput) 0
- } else {
- set PerlmodeVars(perlGetOutput) 1
- }
- }
-
- proc autoSwitch {} {
- global perlMenu PerlmodeVars perlAutoSwitch modifiedModeVars
- lappend modifiedModeVars perlAutoSwitch
- if {$perlAutoSwitch} then {
- set PerlmodeVars(perlAutoSwitch) 0
- } else {
- set PerlmodeVars(perlAutoSwitch) 1
- }
- }
-
- proc overwriteSelection {} {
- global perlMenu perlOverwrite PerlmodeVars modifiedModeVars
- lappend modifiedModeVars perlOverwrite
- if {$perlOverwrite} then {
- set PerlmodeVars(perlOverwrite) 0
- } else {
- set PerlmodeVars(perlOverwrite) 1
- }
- }
-
- proc applyToBuffer {} {
- global perlMenu perlUsebuffer PerlmodeVars modifiedModeVars
- lappend modifiedModeVars perlUsebuffer
- if {$perlUsebuffer} then {
- set PerlmodeVars(perlUsebuffer) 0
- } else {
- set PerlmodeVars(perlUsebuffer) 1
- }
- }
-
- proc promptForArgs {} {
- global perlMenu perlPromptArgs PerlmodeVars modifiedModeVars
- lappend modifiedModeVars perlPromptArgs
- if {$perlPromptArgs} then {
- set PerlmodeVars(perlPromptArgs) 0
- } else {
- set PerlmodeVars(perlPromptArgs) 1
- }
- }
-
- #############################################################################
- # Switch to MacPerl:
- #
- proc macperl {} {
- global macperlPath
- set name [checkRunning MacPerl McPL macperlPath]
- if {[string length $name]} {
- switchTo "MacPerl"
- } else {
- alertnote "Couldn't run MacPerl"
- }
- }
-
- #############################################################################
- # Interact with MacPerl in some other way besides executing a script
- #
- proc perlTellProc {menu name} {
- if {$name == "Open This File"} {
- openInMacperl
- } elseif {$name == "Get Output Window"} {
- openPerlOutput
- } elseif {$name == "Quit"} {
- quitMacperl
- }
- }
-
- #############################################################################
- # Open the current file under MacPerl. This is useful if you want to save it
- # as a droplet or runtime script.
- #
- proc openInMacperl {} {
- global macperlPath
- set name [checkRunning MacPerl McPL macperlPath]
- if {![string length $name]} {
- alertnote "Couldn't run MacPerl"
- }
-
- if {[winInfo dirty]} {
- case [askyesno -c "Save '[lindex [winNames] 0]'?"] in {
- "yes" {save}
- "no" {}
- "cancel" {return}
- }
- }
- switchTo $name
- sendOpenEvent -n $name [lindex [winNames -f] 0]
- }
-
- #############################################################################
- # Quit a running MacPerl app:
- #
- proc quitMacperl {} {
- foreach proc [processes] {
- set sig [lindex $proc 1]
- if {$sig == "McPL"} {
- sendQuitEvent [lindex $proc 0]
- # switchTo is necessary to keep MacPerl from blinking
- switchTo [lindex $proc 0]
- }
- }
- }
-
- #############################################################################
- # Run the selection as a MacPerl script:
- # (No special arrangements are made to provide input or capture the output)
- #
- proc runTheSelection {} {
- global scriptFile scriptStart
- set scriptFile [lindex [winNames -f] 0]
- set scriptStart [lindex [posToRowCol [getPos]] 0]
- perlExecuteScript [getSelect]
- }
-
- proc runTheBuffer {} {
- global scriptFile scriptStart
- set scriptFile [lindex [winNames -f] 0]
- set scriptStart 1
- perlExecuteScript [getText 0 [maxPos]]
- }
-
- proc runAFile {} {
- global scriptFile scriptStart
- if {! [catch {getfile "Select a Perl script"} path]} {
- set scriptFile $path
- set scriptStart 1
- perlExecuteFile $path
- }
- }
-
- #############################################################################
- # Run a preattached Perl text-filter script selected from the menu:
- #
- proc textFiltersProc {menu name} {
- global perlFilterPath scriptFile scriptStart
-
- perlFileAsFilter $perlFilterPath($menu:$name)
- }
-
- #############################################################################
- # Reuse the previous (buffer or file) filter:
- #
- proc repeatLastFilter {} {
- global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
- if {$perlPrevScript != {}} {
- set stype [lindex $perlPrevScript 0]
- set name [lindex $perlPrevScript 1]
- if {$stype == "file"} {
- perlFileAsFilter $name
- } elseif {$stype == "buffer"} {
- perlBufferAsFilter $name
- } else {
- message "Bogus filter name : \"$perlPrevScript\""
- set perlPrevScript {}
- set PerlmodeVars(perlLastFilter) $perlPrevScript
- enableMenuItem $perlMenu repeatLastFilter 0
- }
- }
- }
-
- #############################################################################
- # Ask for a file containing a Perl script to use as a filter:
- #
- proc selectAFile {} {
- global scriptFile scriptStart perlPrevScript
- if {! [catch {getfile "Select a MacPerl script"} path]} {
- perlFileAsFilter $path
- }
- }
-
- #############################################################################
- # Ask for an Alpha buffer containing a Perl script to use as a filter:
- #
- proc selectABuffer {} {
- global scriptFile scriptStart perlPrevScript
-
- set windows [winNames]
- set current [lindex $windows 0]
- if {[llength $windows] > 1} {
- set name [listpick [lsort $windows]]
- if {[string length $name]} {
- # get the full name of the chosen window
- set wname [lindex [winNames -f] [lsearch -exact $windows $name]]
- perlBufferAsFilter $wname
- }
- }
- }
-
- #############################################################################
- # Open a file from the MacPerl application folder - used by "Open Special"
- #
- proc perlOpenFile {menu name} {
- set filename [macperlFolder]$name
- if {[file exists $filename]} {
- edit $filename
- } else {
- alertnote "That file doesn't exist yet"
- }
- }
-
- #############################################################################
- # Support procs
- #############################################################################
-
- #############################################################################
- # Prompt the user to enter a string containing command-line args.
- #
- proc getCmdlineArgs {} {
- global PerlmodeVars
- set oldargs $PerlmodeVars(perlCmdlineArgs)
- if {![catch {prompt "Command-line arguments (if any):" $oldargs} args]} {
- set PerlmodeVars(perlCmdlineArgs) $args
- } else {
- error "getCmdlineArgs: User cancelled"
- }
- return $args
- }
-
- #############################################################################
- # Tell MacPerl to run a script file:
- #
- proc perlExecuteFile {path {args ""}} {
- global ALPHA macperlPath
- global perlGetOutput perlAutoSwitch perlPromptArgs
- global scriptFile scriptStart
-
- if {[string length $path]} {
- set name [checkRunning MacPerl McPL macperlPath]
- if {[string length $name]} {
-
- set scriptFile $path
- set scriptStart 1
-
- # set args [readFileForArgs $path]
- # set args ""
- if {$perlPromptArgs} {
- append args " [getCmdlineArgs]"
- }
-
- sendCloseWinName MacPerl MacPerl
- if {$perlAutoSwitch} then {switchTo $name} else {watchCursor}
- if {[llength $args]} {
- perlDoScript2 "MacPerl" $path $args
- } else {
- dosc -c 'McPL' -t 0 -f $path
- }
- # (not sure which choice is better...)
- # if {!$perlAutoSwitch} then {switchTo $ALPHA}
- switchTo $ALPHA
- #
- if {![getMacPerlError $scriptFile $scriptStart 0]} {
- if {$perlGetOutput} then {openPerlOutput}
- }
- } else {
- alertnote "Couldn't run MacPerl"
- }
- } else {
- alertnote "No file specified to execute"
- }
- }
-
- #############################################################################
- # Run a MacPerl script, passed explicitly as a string:
- #
- # If no "#!/bin/perl" line already exists, one is preprended to the script
- # by wrapSelectScript, which also sets $filterHeadLen for use by
- # getMacPerlError.
- #
- proc perlExecuteScript {script {args ""}} {
- global macperlPath perlGetOutput perlAutoSwitch perlPromptArgs
- global scriptFile scriptStart filterHeadLen ALPHA
- if {$script != ""} {
- set script [wrapSelectScript $script]
- writeScript $script
- set name [checkRunning MacPerl McPL macperlPath]
- if {[string length $name]} {
- # set args [getScriptArgs $script]
- # set args ""
- if {$perlPromptArgs} {
- append args " [getCmdlineArgs]"
- }
- sendCloseWinName MacPerl MacPerl
- if {$perlAutoSwitch} then {switchTo $name} else {watchCursor}
- if {[llength $args]} {
- perlDoScript2 "MacPerl" [scriptPath] $args
- } else {
- dosc -c 'McPL' -t 0 -f [scriptPath]
- }
- # (not sure which choice is better...)
- # if {!$perlAutoSwitch} then {switchTo $ALPHA}
- switchTo $ALPHA
- #
- if {![getMacPerlError $scriptFile $scriptStart $filterHeadLen]} {
- if {$perlGetOutput} then {openPerlOutput}
- }
- } else {
- alertnote "Couldn't run MacPerl"
- }
- } else {
- alertnote "No file specified to execute"
- }
- }
-
- #############################################################################
- # Prepare the contents of a disk file for use as a text-filter script.
- # (calls perlTextFilter to actually run the script)
- #
- proc perlFileAsFilter {path} {
- global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
-
- regexp {(.*):([^:]*)} $path pathname dirname name
-
- set coreScript [readFile $path]
- if {$coreScript != -1} {
- set script [wrapFilterScript $coreScript]
- set scriptFile $path
- set scriptStart 1
- set perlPrevScript [list "file" $path]
- set PerlmodeVars(perlLastFilter) $perlPrevScript
- enableMenuItem $perlMenu repeatLastFilter 1
- message "Running file \"$name\" as text filter ..."
-
- perlTextFilter $script
- } else {
- set perlPrevScript {}
- set PerlmodeVars(perlLastFilter) $perlPrevScript
- enableMenuItem $perlMenu repeatLastFilter 0
-
- alertnote "Couldn't read the script file : $path"
- return
- }
- }
-
- #############################################################################
- # Prepare the contents of a text window for use as a text-filter script.
- # (calls perlTextFilter to actually run the script)
- #
- proc perlBufferAsFilter {wname} {
- global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
-
- regexp {(.*):([^:]*)} $wname pathname dirname name
-
- if {[lsearch [winNames -f] $wname] >= 0} {
- set coreScript [getText -w $wname 0 [maxPos -w $wname]]
-
- # Does it have any text in it?
- if {[string length $coreScript]} {
- set scriptFile $wname
- set scriptStart 1
- set script [wrapFilterScript $coreScript]
- set perlPrevScript [list "buffer" $wname]
- set PerlmodeVars(perlLastFilter) $perlPrevScript
- enableMenuItem $perlMenu repeatLastFilter 1
- message "Running buffer \"$name\" as text filter ..."
-
- perlTextFilter $script
- }
- } else {
- set perlPrevScript {}
- set PerlmodeVars(perlLastFilter) $perlPrevScript
- enableMenuItem $perlMenu repeatLastFilter 0
-
- alertnote "Couldn't find buffer : $name"
- }
- }
-
- #############################################################################
- # Run a Perl script as a command-line text filter, arranging for a text
- # buffer to be attached as standard input. The calling routine should already
- # have processed the script with wrapFilterScript. This routine actually
- # send the script and takes care of writing the input and reading the output
- # files.
- #
- proc perlTextFilter {script {args ""}} {
- global macperlPath perlOverwrite perlUsebuffer perlPromptArgs
- global filterHeadLen scriptFile scriptStart ALPHA
-
- set name [checkRunning MacPerl McPL macperlPath]
- if {![string length $name]} {
- alertnote "Couldn't run MacPerl"
- error "Couldn't run MacPerl"
- }
- writeStdin
- # no longer useful, since errors are (hopefully) trapped now.
- # writeStdout
-
- if {$perlPromptArgs} {
- append args " [getCmdlineArgs]"
- }
-
- sendCloseWinName MacPerl MacPerl
- watchCursor
- perlDoScript2 "MacPerl" [scriptPath] $args [stdinPath]
- switchTo $ALPHA
- if {![getMacPerlError $scriptFile $scriptStart $filterHeadLen]} {
- if {!$perlOverwrite} {new -n {* Perl Output *}}
- if {$perlUsebuffer} {
- pasteStdout 0 [maxPos]
- } else {
- pasteStdout [getPos] [selEnd]
- }
- if {!$perlOverwrite || $perlUseBuffer} {
- catch shrinkWindow
- goto 0
- }
- }
- }
-
- #############################################################################
- # Check the MacPerl output window for error messages.
- #
- proc getMacPerlError {scriptFile scriptStart offset} {
- # global winModes
- set pat0 {^[ \t]*$}
- set pat1 {^#(.*)$}
- set pat2 {File '[^']+'; Line ([0-9]+)}
-
- # first see if there's any output at all
- set nlines [sendCountLines MacPerl MacPerl]
- if {$nlines == 0} {
- return 0
- }
- set errFound 0
- set errMessage {}
- set lines {}
-
- # # read output window one line at a time
- # set nread 0
- # while {$nread < $nlines} {
- # incr nread
- # set line [sendGetText MacPerl MacPerl $nread]
- #[...]
- # }
-
- # read a window-full of MacPerl output (faster, but assumes
- # error message won't appear at the end of a lot of output).
- set maxLines [expr ($nlines > 40)?40:$nlines]
- set output [sendGetText MacPerl MacPerl 1 $maxLines]
- foreach line [split $output "\r"] {
- if {[regexp $pat2 $line mtch num]} {
- set errFound 1
- } elseif {[regexp $pat1 $line mtch err]} {
- if {$errFound == 0} {
- set errMessage $err
- }
- } elseif {[regexp $pat0 $line mtch]} {
- break
- }
- append lines "$line\n"
- }
-
- if {$errFound} {
- new -n {* Perl Error Messages *}
- insertText $lines
- goto 0
- catch {shrinkWindow 1}
- setWinInfo dirty 0
- setWinInfo read-only 1
-
- # Now get the line number associated with the first error
- regexp $pat2 $lines mtch num
- # Convert it to the line number in the original file
- set lineNum [expr $num + $scriptStart - $offset - 1]
- # Bring up the script file and highlight the flagged line
- catch {gotoFileLine $scriptFile $lineNum} fname
- # ... and leave an informative error message
- if {$errMessage != {}} {
- message "$errMessage at Line $lineNum"
- } else {
- message "MacPerl flagged an error at Line $lineNum"
- }
- return 1
-
- } else {
- return 0
- }
- }
-
- #############################################################################
- # Highlight (select) a particular line in the designated file, opening the
- # file if necessary. Returns the full name of the buffer containing the
- # opened file.
- #
- proc gotoFileLine {fname line} {
- if {[expr {[lsearch [winNames -f] "*$fname"] >= 0}]} {
- bringToFront $fname
- } elseif {[expr {[lsearch [winNames] "*$fname"] >= 0}]} {
- bringToFront $fname
- } elseif {[file exists $fname]} {
- edit $fname
- } else {
- alertnote "File \" $fname \" not found." ; return
- }
- set pos [rowColToPos $line 0]
- select [lineStart $pos] [nextLineStart $pos]
- return [lindex [winNames -f] 0]
- }
-
- #############################################################################
- # Take a Perl script and add commands to take the file STDIN as standard
- # input and STDOUT as standard output. This allows scripts written as
- # Unix command-line filters to be used in the (non-MPW) Mac environment as
- # text filters.
- #
- # If there's already a #! line in the script, then the new commands
- # are added after that line. If there was no #! line in the first place,
- # one is added, in case MacPerl is set up to require it (can't hurt...)
- #
- # $filterHeadLen counts the number of lines we add to the top of the
- # original script, so that we can allow for it in interpreting error
- # messages issued by MacPerl.
- #
- proc wrapFilterScript {coreScript} {
- global filterHeadLen
-
- if {[regexp -indices {(#![ !-~]*)} $coreScript allofit cmdln]} {
- set endPos [lindex $cmdln 1]
- set filterHead [string range $coreScript 0 [expr $endPos+1]]
- set coreScript [string range $coreScript [expr $endPos+2] end]
- set filterHeadLen 0
- } else {
- set filterHead "#!/bin/perl\n"
- set filterHeadLen 1
- }
- append filterHead "\$macperlDir = \"[macperlFolder]\" ;\n"
- # Pass the input file as a command-line file arg, instead.
- # append filterHead "open(STDIN, \"<[stdinPath]\" ) ;\n"
- append filterHead "open(STDOUT, \">[stdoutPath]\" ) ;\n"
- append filterHead "select(STDOUT) ;\n\n"
- incr filterHeadLen 6
-
- set filterTail "\nclose STDIN ;\nclose STDOUT ;\n"
-
- set script $filterHead
- append script $coreScript
- append script $filterTail
-
- writeScript $script
- return $script
- }
-
- #############################################################################
- # Add a #!/bin/perl line to the script if it doesn't contain one already.
- # (MacPerl puts up dialog if this line is missing when it expects it,
- # hanging the DoScript and leaving us stuck.)
- #
- proc wrapSelectScript {coreScript} {
- global filterHeadLen
-
- if {![regexp -indices {(#![ !-~]*)} $coreScript allofit cmdln]} {
- set script "#!/bin/perl\n"
- append script $coreScript
- set filterHeadLen 1
- } else {
- set script $coreScript
- set filterHeadLen 0
- }
-
- writeScript $script
- return $script
- }
-
- #############################################################################
- # Paste the text of the file STDOUT in place of the current selection.
- #
- proc pasteStdout {from to} {
- set result [readFile [stdoutPath]]
- if {$result != -1} {
- deleteText $from $to
- insertText $result
- catch shrinkWindow
- goto 0
- } else {
- alertnote "Couldn't find the output file : STDOUT"
- }
- }
- # replaceText [getPos] [selEnd] $result
-
- #############################################################################
- # Extend the current selection to encompass complete lines. If the
- # 'applyToBuffer' flag is checked, then the entire buffer is selected.
- #
- proc completeSelection {} {
- global perlUsebuffer
- if {$perlUsebuffer} {
- set start 0
- set end [maxPos]
- } else {
- set start [lineStart [getPos]]
- set end [nextLineStart [expr [selEnd]-1]]
- }
- if {$end == $start} {set end [nextLineStart [selEnd]]}
- return [list $start $end]
- }
-
- #############################################################################
- # writeStdin: Extend the selection, as appropriate, and write it to the
- # STDIN file in the MacPerl directory.
- # writeStdout: Write the extended selection to the STDOUT file. This will
- # then be the default output in case MacPerl hangs.
- # writeScript: Write the SCRIPT file in the MacPerl directory. MacPerl will
- # read the script from this file.
- #
- proc writeStdin {} {
- set res [completeSelection]
- set tmpfid [open [stdinPath] "w+"]
- puts $tmpfid [eval getText $res]
- close $tmpfid
- }
-
- # This should be unnecessary now that we're watching for MacPerl errors...
- proc writeStdout {} {
- set res [completeSelection]
- set tmpfid [open [stdoutPath] "w+"]
- puts $tmpfid [eval getText $res]
- close $tmpfid
- }
-
- # This will hopefully be unnecessary with the next release of MacPerl...
- proc writeScript {script} {
- set tmpfid [open [scriptPath] "w+"]
- puts $tmpfid $script
- close $tmpfid
- }
-
- #############################################################################
- # Read and return the complete contents of the specified file.
- #
- proc readFile {fileName} {
- if {[file exists $fileName] && [file readable $fileName]} {
- set fileid [open $fileName "r"]
- set contents ""
- while {[gets $fileid nextLine] != -1} {
- append contents $nextLine "\n"
- }
- close $fileid
- return $contents
- } else {
- return -1
- }
- }
-
- #############################################################################
- # Scan a file for a command line, and return the arguments found.
- #
- proc readFileForArgs {fileName} {
- if {[file exists $fileName] && [file readable $fileName]} {
- set fileid [open $fileName "r"]
- set contents ""
- while {[gets $fileid nextLine] != -1} {
- if {[regexp {^[ \t]*#![^ \t]+(.*)$} $nextLine mtch args]} {
- close $fileid
- set args [string trim $args]
- return $args
- }
- }
- close $fileid
- return ""
- } else {
- return -1
- }
- }
-
- #############################################################################
- # Scan a script for a command line, and return the arguments found.
- #
- proc getScriptArgs {script} {
- set lines [split $script "\r"]
- foreach line $lines {
- if {[regexp {^[ \t]*#![^ \t]+(.*)$} $line mtch args]} {
- set args [string trim $args]
- return $args
- }
- }
- return ""
- }
-
- #############################################################################
- # Read the MacPerl output window and load the contents, if any, into
- # a new Alpha window.
- #
- proc openPerlOutput {} {
- set output [sendGetText MacPerl MacPerl]
- if {[string length $output]} {
- new -n {* MacPerl Output *}
- insertText $output
- catch {shrinkWindow 1}
- goto 0
- }
- }
-
- #############################################################################
- # General Apple Event routines
- # (These should work with any application that supports the appropriate events)
- #
-
- # Get the name that Alpha is running under, so we can switch back here
- # explicitly when needed.
- foreach p [processes] {
- if {[lindex $p 1] == "ALFA"} {
- set ALPHA [lindex $p 0]
- break
- }
- }
-
- # AEBuild utility functions
- proc curlyq {str} {
- return "\“$str\”"
- }
- proc AEAbsPos {posName} {
- # (would like to be able to use 'first' and 'last' as well, but haven't yet
- # figured out the correct AEBuild syntax. "seld:abso('firs')" doesn't work.)
- if {$posName > 0} {
- return "form:indx, seld:long($posName)"
- } else {
- error "AEAbsPos: bad argument"
- }
- }
- proc AEName {name} {
- return "form:'name', seld:[curlyq $name]"
- }
- proc AEWinByName {name} {
- return "obj{want:type('cwin'), from:'null'(), [AEName $name] } "
- }
- proc AEWinByPos {absPos} {
- return "obj{want:type('cwin'), from:'null'(), [AEAbsPos $absPos] } "
- }
- proc AELineRange {absPos1 absPos2} {
- set lineObj1 "obj{ want:type('clin'), from:'ccnt'(), [AEAbsPos $absPos1] }"
- set lineObj2 "obj{ want:type('clin'), from:'ccnt'(), [AEAbsPos $absPos2] }"
- return "form:'rang', seld:rang{star:$lineObj1, stop:$lineObj2 } "
- }
-
- # Quit an application.
- proc sendQuitEvent {appname} {
- AEBuild $appname "aevt" "quit"
- }
-
- # Close one of an application's windows, designated by number.
- proc sendCloseWinNum {appname num} {
- AEBuild $appname "core" "clos" "----" [AEWinByPos $num]
- }
-
- # Close one of an application's windows, designated by name.
- proc sendCloseWinName {appname name} {
- AEBuild $appname "core" "clos" "----" [AEWinByName $name]
- }
-
- # Obtain the number of lines in one of an application's
- # windows, designated by name.
- proc sendCountLines {appname name} {
- set winObj [AEWinByName $name]
- set res [AEBuild -r $appname "core" "cnte" "----" $winObj kocl type('clin')]
- if {[regexp {:(.*)\}} $res allofit nlines]} {
- return $nlines
- } else {
- return 0
- }
- }
-
- # Get a selected range of lines from one of an application's
- # windows, designated by name. If $last is missing, then a single
- # line is returned; if both $first and $last are missing, then
- # the complete window contents are returned.
- proc sendGetText {appname name {first {missing}} {last {missing}}} {
- global ALPHA
- set winObj [AEWinByName $name]
- if {$first != "missing"} {
- if {$last != "missing"} {
- set rangDesc [AELineRange $first $last]
- } else {
- set rangDesc [AEAbsPos $first]
- }
- set objDesc "obj{want:type('clin'), from:$winObj, $rangDesc }"
- } else {
- set objDesc "obj{want:type('ctxt'), from:$winObj, form:'indx', seld:abso('all') }"
- }
- set res [AEBuild -r $appname "core" "getd" "----" $objDesc]
- if {![regexp {“.*”} $res text]} { set text {} }
- return [string trim $text {“”}]
- }
-
- # Send a DoScript event, optionally including the special flags recognized
- # by MacPerl. (debugged, but not currently used)
- proc perlDoScript {appname script {flags {}}} {
- if {$script != ""} {
- append descriptor " ---- {[curlyq $script]}"
- } else {
- error "perlDoScript: missing script argument"
- }
- set usrf {}
- if {[lsearch -exact $flags "extract"] >= 0} {
- append usrf { "EXTR" 'true'}
- } elseif {[lsearch -exact $flags "noextract"] >= 0} {
- append usrf { "EXTR" 'fals'}
- }
- if {[lsearch -exact $flags "debug"] >= 0} {
- append usrf { "DEBG" 'true'}
- } elseif {[lsearch -exact $flags "nodebug"] >= 0} {
- append usrf { "DEBG" 'fals'}
- }
- if {[lsearch -exact $flags "preprocess"] >= 0} {
- append usrf { "PREP" 'true'}
- } elseif {[lsearch -exact $flags "nopreprocess"] >= 0} {
- append usrf { "PREP" 'fals'}
- }
- eval "AEBuild -r \"$appname\" misc dosc $descriptor $usrf"
- }
-
- proc perlDoScript2 {appname fname {args {}} {fileArg {}}} {
- set nargs 0
- if {$fname != ""} {
- set argv "\[[curlyq $fname]"
- foreach item [split [join $args " "] " "] {
- set item [string trim $item]
- if {[string length $item]} {
- append argv ", [curlyq $item]"
- incr nargs
- }
- }
- if {[string length $fileArg]} {
- # if {$nargs} {
- # append argv ", [curlyq --]"
- # }
- append argv ", [curlyq $fileArg]"
- }
- append argv "]"
- set reply [eval "AEBuild -r \"$appname\" misc dosc \"----\" [list $argv]"]
- # alertnote $reply
- }
- }
-
- ##############################################################################
- # Automatic subroutine marking for Perl mode in Alpha 5.85
- #
- # (code stolen shamelessly from 'tclMarkFile' in 'tcl.tcl')
- #
- proc PerlMarkFile {} {
- set end [maxPos]
- set pos 0
- set l {}
- while {![catch {search -f 1 -r 1 -m 0 -i 0 {^sub} $pos} res]} {
- set start [lindex $res 0]
- set end [nextLineStart $start]
- set text [lindex [getText $start $end] 1]
- set pos $end
- set inds($text) [lineStart [expr $start - 1]]
- }
-
- if {[info exists inds]} {
- foreach f [lsort [array names inds]] {
- set next [nextLineStart $inds($f)]
- setNamedMark $f $inds($f) $next $next
- }
- }
- }
-
- proc dummyPerl {} {
- }
-
- ##############################################################################
- # Perl mode definitions (for Alpha 5.90)
- #
- lappend modes Perl
- set dummyProc(Perl) dummyPerl
- set modeMenus(Perl) { perlMenu }
- lappend modeSuffixes {*.pl} { set winMode Perl }
- newModeVar Perl elecRBrace {0} 1
- newModeVar Perl elecLBrace {1} 1
- newModeVar Perl electricSemi {0} 1
- newModeVar Perl wordBreak {(\$)?[a-zA-Z0-9_]+} 0
- newModeVar Perl prefixString {# } 0
- newModeVar Perl wordWrap {0} 1
- newModeVar Perl funcExpr {^sub *([+-a-zA-Z0-9]+)} 0
- newModeVar Perl wordBreakPreface {[^a-zA-Z0-9_\$]} 0
- newModeVar Perl optionIsMeta {1} 1
-
- set perlKeywords {
- accept alarm atan2 bind binmode caller chdir chmod chop chown chroot
- close closedir connect continue cos crypt dbmclose dbmopen defined
- delete die do dump each else elsif eof eval exec exit exp fcntl fileno
- flock for foreach fork getc getlogin getpeername getpgrp getppid
- getpriority getgrnam gethostbyname getnetbyname getprotobyname getpwuid
- getgrgid getservbyname gethostbyaddr getnetbyaddr getprotobynumber
- getservbyport getpwent getgrent gethostent getnetent getprotoent
- getservent setpwent setgrent sethostent setnetent setprotoent setservent
- endpwent endgrent endhostent endnetent endprotoent endservent
- getsockname getsockopt gmtime goto grep hex if index int ioctl join keys
- kill last length link listen local localtime log lstat lstat mkdir
- msgctl msgget msgsnd msgrcv next oct open opendir ord pack pipe pop
- print print printf printf push q qq qx rand read readdir readlink recv
- redo rename require reset return reverse rewinddir rindex rindex rmdir
- scalar seek seekdir select semctl semget semop send setpgrp setpriority
- setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep
- socket socketpair sort splice split sprintf sqrt srand stat study sub
- substr symlink syscall sysread system syswrite tell telldir time times
- tr truncate umask undef unless unlink unpack unshift until utime values
- vec wait waitpid wantarray warn while write eq ne cmp lt gt le ge @_ $_ $.
- $/ $, $" $\\ $\# $% $= $- $~ $^ $| $$ $? $& $` $' $+ $* $0 $1 $2 $3 $4 $5
- $6 $7 $8 $9 $[ $] $; $! $@ $< $> $( $) $: $^D $^F $^I $^P $^T $^W $^X
- $ARGV @ARGV @INC %INC $ENV $SIG
- }
- regModeKeywords -e {#} -c red -k blue Perl $perlKeywords
- unset perlKeywords
-
- ##############################################################################
- # Make sure Perl-mode is installed correctly if this file is loaded
- # after the mode-variables menus have already been built.
- #
- set modes [lsort $modes]
- buildFlagsVars
-
- ##############################################################################
-